package com.googlecode.allinclusive.fw.web.struts2.interceptor;

import java.text.MessageFormat;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts2.ServletActionContext;

import com.googlecode.allinclusive.fw.web.valueobject.UserObject;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;

public class LoggingInterceptor extends MethodFilterInterceptor {

	/**
	 * serialVersionUID
	 */
	private static final long serialVersionUID = -3529783996438500645L;
	
	private static final Log log = LogFactory.getLog(LoggingInterceptor.class);
	
	private static final MessageFormat MESSAGE_FORMAT = new MessageFormat("session:{0} user:{1} action:{2}#{3} [{4}]");
	
	protected String doIntercept(ActionInvocation invocation) throws Exception {
		logStart(invocation);
		try {
			return invocation.invoke();
		} catch (Exception ex) {
			log(invocation, ex);
			throw ex;
		} finally {
			logEnd(invocation);
		}
	}
	
	protected void logStart(ActionInvocation invocation) {
		log(invocation, "start");
	}
	
	protected void logEnd(ActionInvocation invocation) {
		log(invocation, "end");
	}
	
	protected void log(ActionInvocation invocation, Object obj) {
		ActionContext ac = invocation.getInvocationContext();
		HttpServletRequest request = (HttpServletRequest) ac.get(ServletActionContext.HTTP_REQUEST);
		HttpSession session = request.getSession();
		// Session ID
		final String sessionId = session.getId();
		// UserObject
		final UserObject userObject = (UserObject) session.getAttribute(UserObject.USER_OBJECT_KEY);
		final String userId;
		if (userObject != null) {
			userId = userObject.getUserId();
		} else {
			userId = null;
		}
		// Action
		final String actionName = invocation.getAction().getClass().getSimpleName();
		final String methodName = invocation.getProxy().getMethod();
		
		/*
		 * LINE 1 : session + user + action + Exception.getMessage();
		 * LINE 2 ~ LINE m : Request Object
		 * LINE m ~ LINE m+n : Session Object
		 * LINE m+n ~ LINE m+n+k : Exception Full StackTrace
		 */
		// TODO ???
		StringBuilder sb = new StringBuilder();
		if (obj instanceof Throwable) {
			Throwable th = (Throwable) obj;
			sb.append(th.getMessage());
			sb.append(Character.LINE_SEPARATOR);
			sb.append("HTTP RESUEST = ");
			sb.append(ToStringBuilder.reflectionToString(request));
			sb.append(Character.LINE_SEPARATOR);
			sb.append("HTTP SESSION = ");
			sb.append(Character.LINE_SEPARATOR);
			sb.append(ToStringBuilder.reflectionToString(session));
			sb.append("EXCEPTION = ");
			sb.append(ExceptionUtils.getFullStackTrace(th));
			log.error(MESSAGE_FORMAT.format(new Object[]{sessionId, userId, actionName, methodName, sb.toString()}));
		} else {
			sb.append(obj);
			log.info(MESSAGE_FORMAT.format(new Object[]{sessionId, userId, actionName, methodName, sb.toString()}));
		}
	}

}
